<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>

    <link rel="stylesheet" type="text/css" 
      href="/assets/css/straybirds.css" media="screen" />
    <link rel="stylesheet" type="text/css" 
      href="/assets/css/pygments.css" media="screen" />

    <!-- MathJax Section Start -->

    <script type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
    </script>
    <script>
        MathJax.Hub.Config({
              tex2jax: {
              skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
              }
        });
        MathJax.Hub.Queue(function() {
            var all = MathJax.Hub.getAllJax(), i;
            for(i=0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

    <!-- MathJax Section End -->

    <!-- Google Analytics Start-->
    <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-48100787-1', 'minixalpha.github.io');
  ga('send', 'pageview');

</script>

    <!-- Google Analytics End -->

    <title>对 Java 内存模型的理解</title>
  </head>

  <body>
    <div class="container">
      <header>
        <div class="container">
          <h1>
              <a href="/" title="Home Page"> 潇湘夜雨 </a>
          <span class="github-src">
            <a href ="https://github.com/minixalpha/minixalpha.github.io"
               target="_blank"
               title="Fork me on GitHub">
              <img src="/assets/images/GitHub-Mark-Light-32px.png" alt="">
            </a>
          </span>
          </h1>
        </div>
      </header>

      <aside id="left-side">
        <h2> 分类 </h2>
  <ul class="category-list">
      
            
                <li>
                <a href="/categories/源代码阅读"> 源代码阅读 (20) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/设计模式"> 设计模式 (3) </a>
                </li>
            
      
            
                <li style="background-color: #444">
                <a href="/categories/科研"> 科研 (6) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/思想"> 思想 (2) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/技术"> 技术 (18) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/工具"> 工具 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/虚拟机"> 虚拟机 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/java"> java (11) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/c语言"> c语言 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/读书"> 读书 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/操作系统"> 操作系统 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/英语"> 英语 (10) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/计算机系统"> 计算机系统 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/生活"> 生活 (1) </a>
                </li>
            
      
  </ul>

      </aside>

      <aside id="right-side">
        <h2> 归档 </h2>
  <ul class="archive-list">
    
    
    
        
        
        
        
            
            <li>
                <a href="/2014/08">
                    2014-08 (1)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/07">
                    2014-07 (5)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/05">
                    2014-05 (12)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/04">
                    2014-04 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/03">
                    2014-03 (11)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/02">
                    2014-02 (6)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/01">
                    2014-01 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/11">
                    2013-11 (10)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/10">
                    2013-10 (3)
                </a>
            </li>

        
        
    
        
        
        
        
            
            <li>
                <a href="/2010/09">
                    2010-09 (1)
                </a>
            </li>

        
        
    
  </ul>

      </aside>

      <article>

<h1>对 Java 内存模型的理解</h1>

<h2>Java 内存模型</h2>

<p>Java内存模型规定了在多线程程序中，什么样的行为是允许出现的，什么样的行为是禁止出现的。这样说可能有点抽象，我们换一个角度。将程序行为抽象成读操作和写操作，每个线程有自己的局部变量，同时线程之间还存在共享变量。那么一个多线程程序执行结束后，所有变量会有一个最终值。Java内存模型来决定什么样的值合法，什么样的值不合法。</p>

<p>内存模型不能要求的太严格，这样会阻碍很多优化方法，降低程序执行的效率，但也不能要求的太松，因为这样会导致一些执行结果违反我们的直觉。例如指令间的重排序问题，如果线程内部的指令完全按照程序中指明的次序执行，并且每次执行一条指令，执行的结果立即生效，那么就会阻碍很多优化方法，但这样对程序员是有好处的，因为程序员很容易推断程序的执行结果，这样写出的程序就容易与自己的意图一致。这种内存模型被称为顺序一致性模型(Sequential Consistency)。反之，如果为了优化程序执行效率，重排序的可能性有很多，那么程序的效率是提高了，但对程序员来说，就很难推断程序的执行结果。这一类的内存模型被称为Relaxed Memory Model。</p>

<p>这样，我们就遇到了一个两难的问题：</p>

<ul>
<li>内存模型要求严格，那么程序效率低，但程序员容易写对</li>
<li>内存模型要求松，那么程序效率高，但程序员不容易写对</li>
</ul>

<p>而程序的效率，与程序是否容易写对都很重要。为了解决这个问题，科学家提出了 Data Race Free 的概念，它是对多线程程序同步程度的一种描述，基本的思想是如果多线程程序进行了正确的同步，那么程序员就可以按照顺序一致性模型去推断程序的执行结果，而底层对内存操作的实现，可以按照 Relaxed Memory Model进行优化。</p>

<p>Java 内存模型包含了两方面的内容</p>

<ul>
<li>对正确同步的多线程程序，保证其执行结果与在顺序内存模型下执行的结果一致</li>
<li>对没有正确同步要求的多线程程序，进行一定程度的限制，以保证安全性</li>
</ul>

<p>其中第一方面是与 Data Race Free相关的，第二方面与后面介绍的 Causality Requirements 相关。</p>

<h2>Data Race Free</h2>

<p>Java 内存模型其实定义了好几个概念来说明什么是正确的同步。</p>

<ul>
<li>冲突访问(conflicting accesses)</li>
</ul>

<p>如果存在多个线程，同时访问同一地址，并且至少有一个是写操作，那么这个程序存在冲突访问</p>

<ul>
<li>happen-before order</li>
</ul>

<p>两个操作之间如果满足下面任意一个条件，就可以说这两个操作之间存在 happen-before order:</p>

<ol>
<li>同一个线程内，在程序中有先后次序的操作</li>
<li>构造器的结尾的操作与 finalize 函数的开始的操作</li>
<li>unlock 操作与所有同一把锁上的 lock操作</li>
<li>volatile 变量的读操作与所有对它的写操作</li>
<li>对变量默认值的写操作与线程启动后的第一个操作</li>
<li>如果线程 T2 检测到线程 T1 终止执行，那么 T1 的最后一次操作与 T2任意操作</li>
<li>启动一个线程的操作与此线程内第一个操作</li>
<li>如果线程 T1 中断了线程 T2，那么此中断操作与其它任何看到 T2 被中断的操作之间。</li>
</ol>

<p>其中有些我也不是很理解。。</p>

<ul>
<li>data race free</li>
</ul>

<p>所有存在冲突访问的操作之间都有 happen-before order，那么此多线程程序满足 data race free</p>

<ul>
<li>正确同步 </li>
</ul>

<p>假如多线程程序在顺序一致性模型下执行，如果它满足 data race free，那么此程序进行了正确的同步。</p>

<p>正确同步的多线程程序，其执行结果与在顺序一致性模型下的执行结果一致。仔细体会下概念之间的关系。有点绕。</p>

<p>另一方面，如果程序没有正确同步，执行结果也不是任意的，必须对其进行限制，但限制又不能太强，因为太强会阻碍优化。所以 Java 内存模型使用了 Causality Requirements 的概念。</p>

<h2>Causality Requirements</h2>

<p>为了精确定义内存模型，Java语言规范中，提出了 Causality Requirements 的概念。不知道是什么原因，这个概念很少被提及，但是我觉得它是很重要的，但同时，也是非常令人费解的。语言规范中，首先定义了 Well-Formed Executions 的概念，现在对内存模型的很多讨论，都是在这一层，它包括了对多线程程序执行中，与锁，volatile变量，执行次序等等相关的规定。如果一个多线程程序的执行满足这些规定，那么这个执行就是 Well-Formed Executions 的。国内有一个系列文章《<a href="http://ifeve.com/java-memory-model-0/">深入理解Java内存模型</a>》，主要是在这方面描述Java内存模型。此外，在 Java 并发领域内著名的 Doug Lea 也给出了一个 <a href="http://gee.cs.oswego.edu/dl/jmm/cookbook.html">The JSR-133 Cookbook for Compiler Writers</a>，为编译器作者们提供参考,探讨的也是这方面的问题。但是，内存模型对多线程程序的执行是否合法，不仅仅要看它是否是 Well-Formed Executions，这次执行还需要满足 Causality Requirements。</p>

<p>语言规范中规定了一个构造过程，如果通过这个构造过程，可以构造出多线程程序最终的执行结果，那么这次执行就满足 Causality Requirements。构造过程从一个空集合C0开始，每次将其中添加若干操作，如果所有操作都能被添加，那么构造成功。即，</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">C0 -&gt; C1 -&gt; C2 -&gt; ... -&gt; C
</code></pre></div>
<p>其中 C<em>i 是 C</em>(i+1) 的子集。你可能注意到了，之前说的“操作能被添加”，什么叫操作能被添加呢？语言规范中规定了，每一个 Ci 都对应一个 Ei，所有 Ei 都要满足 Well-Formed Executions。也就是说，如果你添加了操作后，对应的 Ei 不满足 Well-Formed Executions，那么这个操作就不能被添加。如果最终，你的多线程程序无法构造出这样一个执行链，那么，它的执行结果是非法的。</p>

<p>另外，Java 内存模型最初论文作者维护了一个页面 <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/">The Java Memory Model</a>，其中有一个条目叫 <a href="http://www.cs.umd.edu/%7Epugh/java/memoryModel/CausalityTestCases.html">Causality Test Cases</a>，给出了一些小例子，以便人们明白哪些行为是满足 Causality Requirements 的，哪些是不满足的。此外，在 Java 并发领域内著名的 Doug Lea 也给出了一个 <a href="http://gee.cs.oswego.edu/dl/jmm/cookbook.html">The JSR-133 Cookbook for Compiler Writers</a>，为编译器作者们提供参考。不过据说这份规范有些地方要求太严格了，开发者们还是根据Java语言规范和虚拟机规范来开发。</p>


      </article>

      <div class="comments">
        
          <div id="disqus_thread"></div>
 <script type="text/javascript">
     /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
     var disqus_shortname = 'minixalpha'; // required: replace example with your forum shortname

     /* * * DON'T EDIT BELOW THIS LINE * * */
     (function() {
         var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
         dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
         (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
     })();
 </script>
 <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
    

        
      </div>


      <footer>
        Copyright (c) minixalpha 2014
      </footer>

    </div>
  </body>
</html>
